package fun.ltool.core.excel.handler;

import fun.ltool.core.excel.annotation.ExcelEntity;
import fun.ltool.core.excel.annotation.ExcelField;
import fun.ltool.core.exceptions.ExcelException;
import fun.ltool.core.reflect.ReflectUtil;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * Excel数据映射 数据表模式 处理类
 *
 * @author huangrongsong
 * @since 1.3
 */
public class ExcelDataTableHandler<D> extends ExcelBaseHandler<D> {

    public ExcelDataTableHandler(List<List<Object>> data, Class<D> excelDataClass, ExcelEntity excelEntity, Field[] fields) {
        super(data, excelDataClass, excelEntity, fields);
    }

    /**
     * 映射数据到实体
     *
     * @return 返回数据
     */
    public D build() {
        // 表格数据
        List<List<Object>> list;
        // 处理读取行数
        list = getRowRangeLists();
        if (list == null || list.isEmpty()) {
            throw new ExcelException("未读取到数据，请检查数据是否为空和JavaBean注解是否正确配置");
        }
        D excelDataBean;
        try {
            // 实例化对象
            excelDataBean = excelMappingClass.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new ExcelException("实例化Excel映射对象失败", e);
        }
        // 映射到bean
        ReflectUtil.buildClass(excelDataBean).executor(e -> e.fields(f -> {
            for (Field field : fields) {
                ExcelField excelField = field.getAnnotation(ExcelField.class);
                // 获取数据Excel单元格位置
                int[] cellPosition = excelField.cellPosition();
                // 获取行数据
                List<Object> row = list.get(cellPosition[0]);
                List<Object> columns = getColumnRangeLists(row);
                // 判断是否匹配行列字段名
                String[] cellNames = excelField.cellName();
                if (cellNames.length != 0) {
                    if (cellNames.length != 2) {
                        throw new ExcelException("Excel实体映射 注解：@ExcelField 的属性cellNames配置有误请检查, 实体：" + excelMappingClass.getName() + "字段：" + field.getName());
                    }
                    String rowFieldName = cellNames[0];
                    String columnFieldName = cellNames[1];
                    // 行字段名所在位置
                    int[] rowNamePosition = excelField.rowNamePosition();
                    // 列字段名所在位置
                    int[] columnNamePosition = excelField.columnNamePosition();
                    // Excel行字段名
                    String excelRowFieldName = row.get(0).toString();
                    if (rowNamePosition.length != 0) {
                        excelRowFieldName = getCell(rowNamePosition, list).toString();
                    }
                    // Excel列字段名
                    String excelColumnFieldName = list.get(0).get(cellPosition[1]).toString();
                    if (columnNamePosition.length != 0) {
                        excelColumnFieldName = getCell(columnNamePosition, list).toString();
                    }
                    // 校检字段名
                    if (!Objects.equals(rowFieldName, excelRowFieldName) || !Objects.equals(columnFieldName, excelColumnFieldName)) {
                        if (excelField.isThrowError()) {
                            throw new ExcelException("Excel实体映射赋值校检字段名失败, 实体：" + this.excelMappingClass.getName() + ",字段名：" + field.getName() +
                                    ",注解配置Excel单元格位置" + Arrays.toString(excelField.cellPosition()) +
                                    "字段名配置：" + Arrays.toString(cellNames) +
                                    "校检字段名配置：rowNamePosition=" + Arrays.toString(rowNamePosition) + ",columnNamePosition=" + Arrays.toString(columnNamePosition) +
                                    ",实际获取到的行字段名：" + excelRowFieldName + ",列字段名：" + excelColumnFieldName);
                        }
                    }
                }
                Object value = null;
                // 避免空指针
                if (columns.size() > cellPosition[1]) {
                    value = columns.get(cellPosition[1]);
                }
                // 转换值
                try {
                    value = convertValue(value, field.getType(), excelField.typeConverter());
                } catch (Exception ex) {
                    if (excelField.isThrowError()) {
                        throw new ExcelException(!excelField.message().isEmpty() ? excelField.message() : ex.getMessage(), ex);
                    }
                }
                try {
                    // 赋值
                    f.set(field.getName(), value);
                } catch (Exception ex) {
                    if (excelField.isThrowError()) {
                        throw new ExcelException(!excelField.message().isEmpty() ? excelField.message() : "Excel实体映射赋值失败, 实体：" + this.excelMappingClass.getName() + ",字段名：" + field.getName() + ",注解配置Excel单元格位置" + Arrays.toString(excelField.cellPosition()), ex);
                    }
                }
            }
        })).build();
        return excelDataBean;
    }


}
